using System.Collections.Generic;
using Gameplay.PVE.Config;
using Gameplay.PVE.Entity;
using Gameplay.PVE.Utils;
using UnityEngine;
using Yoozoo.Gameplay.RTS;

namespace Gameplay.PVE
{
    public class PveTargetSearchHelper
    {
        public delegate Vector3 RegionAdapter(Vector3 position);
        
        public static bool CheckDirector(Vector3 position, int width, int height)
        {
            return PveFindPathManager.Instance.CheckIsClear(position,width,height);
        }

        public static bool GetObstacleAutoPosition(ref Vector3 originPosition, int width, int height,int range = 5,RegionAdapter regionAdapter = null)
        {
            return PveFindPathManager.Instance.FindValidPosition(ref originPosition, width, height,range,regionAdapter);
        }

        public static void GetCandidates(UnitBase unit,PveSkillConfig skillConfig, ref List<UnitBase> candidates)
        {
            candidates.Clear();
            var team = unit.Data.GetTargetTeam(skillConfig.search_team);
            var teamList = UnitManager.Instance.GetAllUnitByTeam(team);
            for (int i = 0; i < teamList.Count; i++)
            {
                var candidate = teamList[i];
                if (candidate.Data.team != unit.Data.team && (!candidate.Data.selectable || candidate.Data.invulnerable || !candidate.Data.IsInScreen()))
                {
                    continue;
                }
                if (CheckIsInTagList(unit, candidate, skillConfig))
                {
                    candidates.Add(candidate);
                }
            }
        }

        public static int GetDirectorResourceByBulletConfig(PveSkillBulletConfig config)
        {
            var directorResId = config.director_type;
            if (config.director_type == 1)
            {
                if (config.director_args.TryGetValue("angle", out var angle))
                {
                    if (angle == 30)
                    {
                        directorResId = 11;
                    }
                    else if (angle == 45)
                    {
                        directorResId = 12;
                    }
                    else if (angle == 60)
                    {
                        directorResId = 13;
                    }
                    else if (angle == 90)
                    {
                        directorResId = 14;
                    }
                    else if (angle == 120)
                    {
                        directorResId = 15;
                    }
                    else if (angle == 180)
                    {
                        directorResId = 16;
                    }
                }
            }
            return directorResId;
        }
        public static bool CheckIsInTagList(UnitBase source,UnitBase target,PveSkillConfig skillConfig)
        {
            if (target.Data.team != source.Data.GetTargetTeam(skillConfig.search_team))
            {
                return false;
            }

            for (int i = 0; i < skillConfig.search_tag_black_list.Count; i++)
            {
                int tag = skillConfig.search_tag_black_list[i];
                if (target.Data.tagList.ContainsKey(tag))
                {
                    if (tag == 4)
                    {
                        if (target == source)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            for (int i = 0; i < skillConfig.search_tag_list.Count; i++)
            {
                int tag = skillConfig.search_tag_list[i];
                if (target.Data.tagList.TryGetValue(tag, out var tagValue))
                {
                    if (tag == 1 || tag == 2 || tag == 3)
                    {
                        return true;
                    }
                    else if (tag == 4 && target == source)
                    {
                        return true;
                    }
                    else if (tag == 5 && tagValue == source.Data.id)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        
        public static void CheckTarget(PveSkillBulletConfig skillConfig,Vector3 startPosition,Vector3 targetPosition,Vector3 targetForward,ref List<UnitBase> candidates,ref List<UnitBase> targetList)
        {
            targetList.Clear();
            if (skillConfig.director_type == 4)
            {    
                //自动选敌
                float distance = 0;
                skillConfig.director_args.TryGetValue("distance", out distance);
                for (int i = 0; i < candidates.Count; i++)
                {
                    if (distance != 0)
                    {
                        var d2 = (candidates[i].Data.position - startPosition).sqrMagnitude;
                        if (d2 <= distance * distance)
                        {
                            targetList.Add(candidates[i]);
                        }
                    }
                    else
                    {
                        targetList.Add(candidates[i]);
                    }
                }
            }
            else if (skillConfig.director_type == 1)
            {
                //扇形索敌
                float maxAngle = skillConfig.director_args["angle"];
                float radius = skillConfig.director_args["radius"];
               
                for (int i = 0; i < candidates.Count; i++)
                {
                    float angle = Vector3.Angle(targetForward, candidates[i].Data.position - startPosition);
                    float distance = Vector3.Distance(startPosition, candidates[i].Data.position);
                    if (angle <= maxAngle * 0.5f && distance <= radius)
                    {
                        targetList.Add(candidates[i]);
                    }
                }
            }
            else if (skillConfig.director_type == 0)
            {
                //单个
                float autoChooseDistance = 100;
                float distance = float.MaxValue;
                UnitBase target = null;
                for (int i = 0; i < candidates.Count; i++)
                {
                    var d = Vector3.Distance(candidates[i].Data.position, targetPosition);
                    if (d <= autoChooseDistance && d < distance)
                    {
                        target = candidates[i];
                        distance = d;
                    }
                }
                if (target != null)
                {
                    targetList.Add(target);
                }
            }
            else if (skillConfig.director_type == 3 || skillConfig.director_type == 5)
            {
                //圆形索敌
                float radius = skillConfig.director_args["radius"];
               
                for (int i = 0; i < candidates.Count; i++)
                {
                    float distance = Vector3.Distance(targetPosition, candidates[i].Data.position);
                    if (distance <= radius)
                    {
                        targetList.Add(candidates[i]);
                    }
                }
            }
            else if (skillConfig.director_type == 2)
            {
                float width = skillConfig.director_args["width"];
                float height = skillConfig.director_args["height"];
                //方形索敌
                for (int i = 0; i < candidates.Count; i++)
                {
                    Vector3 offset = candidates[i].Data.position - startPosition;
                    Vector3 centerLine = targetPosition - startPosition;
                    float distance = offset.magnitude;
                    float angle = Vector3.Angle(offset, centerLine);
                    if (angle >= 90)
                    {
                        continue;
                    }
                    float rad = angle * Mathf.Deg2Rad;
                    float distanceToCenter = Mathf.Sin(rad) * distance;
                    float distanceToBottom = Mathf.Cos(rad) * distance;
                    if (distanceToCenter <= width / 2 && distanceToBottom <= height)
                    {
                        targetList.Add(candidates[i]);
                    }
                }
            }
            else if (skillConfig.director_type == 6)
            {
                targetList.AddRange(candidates);
            }
        }

        public static Vector3 GetAutoSkillPosition(ref List<UnitBase> candidates,PveSkillBulletConfig config,UnitBase source,int searchSort,float distanceLimit = 0)
        {
            if (config == null)
            {
                return candidates[0].Data.position;
            }
            if (searchSort == 10)//寻找可以丢到最多敌人的点
            {
                if (config.director_type == 3)
                {
                    if (config.director_args.TryGetValue("radius",out var radius))
                    {
                        //先寻找候选人所包围的矩形
                        var minX = float.MaxValue;
                        var minZ = float.MaxValue;
                        var maxX = 0f;
                        var maxZ = 0f;
                        for (int i = 0; i < candidates.Count; i++)
                        {
                            var candidate = candidates[i];
                            var position = candidate.Data.position;
                            if (minX > position.x)
                            {
                                minX = position.x;
                            }

                            if (minZ > position.z)
                            {
                                minZ = position.z;
                            }

                            if (maxX < position.x)
                            {
                                maxX = position.x;
                            }

                            if (maxZ < position.z)
                            {
                                maxZ = position.z;
                            }
                        }
                        
                        //在矩形里采样
                        var candidatePosition = Vector3.zero;
                        var candidateDistance = float.MaxValue;
                        var coverEnemyNum = 0;
                        float stepX = 0.2f;
                        float stepZ = 0.2f;
                        for (float x = minX; x <= maxX; x += stepX)
                        {
                            for (float z = minZ; z <= maxZ; z += stepZ)
                            {
                                int enemyNum = 0;
                                var samplePosition = new Vector3(x, 0, z);
                                if (distanceLimit > 0 &&
                                    !IsInCircle(samplePosition, source.Data.position, distanceLimit))
                                {
                                    continue;
                                }
                                for (int i = 0; i < candidates.Count; i++)
                                {
                                    if (IsInCircle(samplePosition, candidates[i].Data.position, radius))
                                    {
                                        enemyNum++;
                                    }
                                }
                                if (enemyNum == coverEnemyNum)
                                {
                                    var distance = Vector3.Distance(samplePosition, source.Data.position);
                                    if (distance < candidateDistance)
                                    {
                                        candidatePosition = samplePosition;
                                        candidateDistance = distance;
                                    }
                                }
                                else if (enemyNum > coverEnemyNum)
                                {
                                    var distance = Vector3.Distance(samplePosition, source.Data.position);
                                    coverEnemyNum = enemyNum;
                                    candidatePosition = samplePosition;
                                    candidateDistance = distance;
                                }
                            }
                        }

                        if (candidatePosition != Vector3.zero)
                        {
                            return candidatePosition;
                        }
                    }
                }
            }
            
            Sort(ref candidates,source,searchSort); 
            return candidates[0].Data.position;
                
        }

        private static bool IsInCircle(Vector3 position,Vector3 circleCenter,float radius)
        {
            return Vector3.Distance(position, circleCenter) <= radius;
        }
        

        private static UnitBase unit;

        public static void Sort(ref List<UnitBase> candidates, UnitBase source,int searchSort)
        {
            unit = source;
            if (searchSort == 0)
            {
                candidates.Sort(SortDistanceManhattan);
            }
            else if (searchSort == 1)
            {
                candidates.Sort(SortDistanceMax);
            }
            else if (searchSort == 2)
            {
                candidates.Sort(SortHpPercentMin);
            }
            else if (searchSort == 3)
            {
                candidates.Sort(SortHpPercentMax);
            }
            else if (searchSort == 4)
            {
                candidates.Sort(SortBack);
            }
            else if (searchSort == 5)
            {
                BattleUtils.Shuffle(ref candidates);
            }
        }

        private static int SortBack(UnitBase a, UnitBase b)
        {
            if (a.Data.positionType == b.Data.positionType)
            {
                return Vector3.Distance(a.Data.position, unit.Data.position)
                    .CompareTo(Vector3.Distance(b.Data.position, unit.Data.position));
            }
            return b.Data.positionType.CompareTo(a.Data.positionType);
        }

        private static int SortHpPercentMin(UnitBase a, UnitBase b)
        {
            return (a.Data.CurrentHp / a.Data.TotalHp).CompareTo(b.Data.CurrentHp / b.Data.TotalHp);
        }
        
        private static int SortHpPercentMax(UnitBase a, UnitBase b)
        {
            return (b.Data.CurrentHp / b.Data.TotalHp).CompareTo(a.Data.CurrentHp / a.Data.TotalHp);
        }

        private static int SortDistanceManhattan(UnitBase a, UnitBase b)
        {
            return PveUtils.GetManhattanDistance(a.Data.position,unit.Data.position).CompareTo(PveUtils.GetManhattanDistance(b.Data.position,unit.Data.position));
        }
        
        private static int SortDistanceMin(UnitBase a, UnitBase b)
        {
            return Vector3.Distance(a.Data.position, unit.Data.position)
                .CompareTo(Vector3.Distance(b.Data.position, unit.Data.position));
        }
        
        private static int SortDistanceMax(UnitBase a, UnitBase b)
        {
            return Vector3.Distance(b.Data.position, unit.Data.position)
                .CompareTo(Vector3.Distance(a.Data.position, unit.Data.position));
        }
    }
}